FireLens(Fluent Bit)CloudWatch Logsの新プラグインを使ったログストリーム作成の注意点
ECSのタスク(コンテナ)のログ出力先を変更できるFireLens機能があります。FireLensでFluent Bitを起動し、プラグインを利用し各種ログ保存先へ振り分けます。CloudWatch Logsや、Kinesis Firehose経由S3保存をよく利用されているのではないでしょうか。
そのプラグインは現在、新旧の2種類存在しています。ぱっと見はプラグインの指定方法が微妙に違うくらいです。
詳細は以下のリンクをご確認ください。
本記事ではCloudWatch Logsへログを送信する新旧プラグインについて取り上げます。以下の意味を理解せず「ロググループとログストリームのテンプレーティング?うーん、一般的な設定しかしてないからたぶんヨシ!」で失敗したため、新プラグイン利用時の注意事項を紹介します。
Do you plan to deprecate this older plugin? At this time, we do not. This plugin will continue to be supported. It contains features that have not been ported to the higher performance version. Specifically, templating of log group name and streams. Some users will continue to need the features of this plugin.
引用: aws/amazon-cloudwatch-logs-for-fluent-bit: A Fluent Bit output plugin for CloudWatch Logs
結論
ECSメタデータを利用した変数を使いロググループや、ログストリームを作成したい場合は
- 旧プラグイン(
cloudwatch
)しか対応していない - 新プラグイン(
cloudwatch_logs
)は未対応なため変数を使うと期待通りの動きをしない
新プラグインの利用
新プラグインの利用はName
にcloudwatch_logsを指定します。
ロググループ作成失敗編
ECSメタデータの変数を利用します。ロググループはECSクラスター名の名前で作成し、ログストリーム名はタスクごとに個別のストリームを作成したいのでタスクIDを末尾に付与します。
[SERVICE] Flush 1 Grace 30 [FILTER] Name grep Match webapp-firelens* Exclude log ^(?=.*ELB-HealthChecker\/2\.0).*$ [OUTPUT] Name cloudwatch_logs Match webapp-firelens* region ap-northeast-1 log_group_name /ecs/logs/$(ecs_cluster_name) log_stream_name webapp-$(ecs_task_id) auto_create_group true
上記設定ファイルをFireLensで起動するFluent Bitのイメージにコピーして検証します。
FROM public.ecr.aws/aws-observability/aws-for-fluent-bit:2.19.0 COPY ./extra.conf /fluent-bit/etc/extra.conf
実行結果
FireLensのログを確認します。${ecs_cluster_name}
の変数を展開できなかったようです。ロググループの作成に失敗しています。
[ info] [output:cloudwatch_logs:cloudwatch_logs.0] Creating log group /ecs/logs/$(ecs_cluster_name) [error] [output:cloudwatch_logs:cloudwatch_logs.0] Failed to create log group
ログストリーム作成失敗編
ロググループ名は変数を使わずベタ書きに修正しました。ログストリームは引き続き変数を利用します。
[SERVICE] Flush 1 Grace 30 [FILTER] Name grep Match webapp-firelens* Exclude log ^(?=.*ELB-HealthChecker\/2\.0).*$ [OUTPUT] Name cloudwatch_logs Match webapp-firelens* region ap-northeast-1 log_group_name /ecs/logs/test-gorup log_stream_name webapp-$(ecs_task_id) auto_create_group true
実行結果
ログストリーム名が指定したまま(webapp-$(ecs_task_id)
)の名前で作成されています。変数を展開できてないことがわかりました。
FireLensのログも確認します。そのままwebapp-$(ecs_task_id)
の名前でログストリームを作成していることがわかります。
[ info] [output:cloudwatch_logs:cloudwatch_logs.0] Created log group /ecs/logs/test-gorup [ info] [output:cloudwatch_logs:cloudwatch_logs.0] Creating log stream webapp-$(ecs_task_id) in log group /ecs/logs/test-gorup
旧プラグインを利用
Name
にcloudwatchを指定(末尾_logs
を削除)し、旧プラグインに切り替えます。
成功編
新プラグインのロググループ作成失敗編の設定ファイルと、Name
でプラグイン名指定の違いしかありません。
[SERVICE] Flush 1 Grace 30 [FILTER] Name grep Match webapp-firelens* Exclude log ^(?=.*ELB-HealthChecker\/2\.0).*$ [OUTPUT] Name cloudwatch Match webapp-firelens* region ap-northeast-1 log_group_name /ecs/logs/$(ecs_cluster) log_stream_name webapp-$(ecs_task_id) auto_create_group true
実行結果
期待通りの結果です。旧プラグインで変数を展開してロググループ、ログストリームを作成できました。新プラグインと挙動の違いがわかりました。
time="2021-08-11T09:07:58Z" level=info msg="[cloudwatch 0] Created log group /ecs/logs/arn.aws.ecs.ap-northeast-1.123456789012.cluster/sample-dev-cluster\n" time="2021-08-11T09:07:58Z" level=info msg="[cloudwatch 0] Created log stream webapp-3edb579771ff40fcb7e536040929a17c in group /ecs/logs/arn.aws.ecs.ap-northeast-1.123456789012.cluster/sample-dev-cluster"
存在しない変数を使った場合の挙動
$(ecs_cluster_name)
という未定義の変数を指定してロググループを作成してみます。これに関してはただ気になったから試しただけです。
[SERVICE] Flush 1 Grace 30 [FILTER] Name grep Match webapp-firelens* Exclude log ^(?=.*ELB-HealthChecker\/2\.0).*$ [OUTPUT] Name cloudwatch Match webapp-firelens* region ap-northeast-1 log_group_name /ecs/logs/$(ecs_cluster_name) log_stream_name webapp-$(ecs_task_id) auto_create_group true
実行結果
fluentbit-defaultの名前でロググループが作成されました。ログストリーム名は指定通りに作成されています。新プラグイン同様にロググループ作成できないエラーを期待していました。新旧プラグインではこういったところにも違いありました。
FireLensのログを確認します。
AWS for Fluent Bit Container Image Version 2.19.0time="2021-08-11T08:58:49Z" level=info msg="[cloudwatch 0] plugin parameter log_group_name = '/ecs/logs/$(ecs_cluster_name)'" time="2021-08-11T08:58:49Z" level=info msg="[cloudwatch 0] plugin parameter default_log_group_name = 'fluentbit-default'"
古いプラグインが提供され続けている理由とは
初心に帰り説明を読み直します。
templating of log group name and streamsがリンクになっています。リンク先を確認すると「用意されている変数名はなんだっけな?」とよく確認するページでした。そして、これが「一部ユーザは引き続きこの機能を必要とするでしょう」という文に繋がるわけですね。
そうか、みんなECSメタデータの変数使っていなかったのか...本当にそうなの?
CloudWatch Logsへログを送信する場合、復数のFireLens(Fluent Bit)コンテナから単一のログストリームに送るとスロットリングエラーを起こす可能性が高くなります。タスクIDかなにかを利用しユニークなログストリームを作成し、タスク(アプリケーションコンテナ)ごとに個別のログストリームにログを送信して回避したいところだと思います。
もしかしたら、私が知らないだけで他の回避方法があるかもしれません。少なくとも用意されている変数が新プラグインでは使えないことがわかりました。(ちゃんと説明されていました)
2021/9/17追記他の回避方法は以下のリンクをご確認ください
まとめ
新旧どちらのプラグインを使えばよいのかの判斷基準として、ECSメタデータを利用した変数は旧プラグイン(cloudwatch)でしか利用できない。変数を使わないで設定で済むなら新プラグイン(cloudwatch_logs)の方が高性能なので採用を検討したい。
おわりに
なにげなく新プラグインを利用してたときはログストリーム名にタスクIDを付与せず、単一のログストリームでテストしていたので気づきませんでした。まじめに設定しようと旧プラグインの設定ファイルを参考にプラグイン名(Name
)だけを新プラグイン名に書き換えて実行したときに気づきました。タスクIDなどの変数以外でユニークなログストリーム名を生成できるならよかったのですが、他の方法が思いつかなかったです。
どなたかの参考になれば幸いです。